﻿using System;
using System.Collections.Generic;
using System.Text;
using MemoryGameBL;
using Ex02.ConsoleUtils;

namespace C11_Ex02
{
    public class UIHandler
    {
        private bool m_shouldExitFromGame = false;
        private Game m_Game;

        /// <summary>
        /// Starts the Memory Game.
        /// </summary>
        public void StartGame()
        {
            m_Game = initGame();

            while (!m_shouldExitFromGame)
            {
                BoardConsoleDrawer boardConsoleDrawer = new BoardConsoleDrawer();
                Screen.Clear();

                this.initRound();

                if (!m_shouldExitFromGame)
                {
                    Screen.Clear();
                    boardConsoleDrawer.DrawBoard(m_Game.PlayingBoard);

                    while (!m_Game.IsGameEnded && !m_shouldExitFromGame)
                    {
                        Screen.Clear();
                        boardConsoleDrawer.DrawBoard(m_Game.PlayingBoard);

                        if (m_Game.CurrentPlayerType == Game.eOpponentType.Human)
                        {
                            Player currentPlayer = m_Game.CurrentlyPlayingPlayer;
                            if (currentPlayer != null)
                            {
                                string messageToUser = string.Format("{0}, please type the 1st cell you would like to show.{1}", currentPlayer.Name, Environment.NewLine);

                                Cell firstCell = getCellFromUser(messageToUser);
                                if (!m_shouldExitFromGame)
                                {
                                    Board currentBoard = m_Game.OpenCell(firstCell);
                                    Screen.Clear();
                                    boardConsoleDrawer.DrawBoard(currentBoard);

                                    messageToUser = string.Format("{0}, please type the 2nd cell you would like to show.{1}", currentPlayer.Name, Environment.NewLine);

                                    Cell secondCell = getCellFromUser(messageToUser);
                                    if (!m_shouldExitFromGame)
                                    {
                                        currentBoard = m_Game.OpenCell(secondCell);
                                        Screen.Clear();
                                        boardConsoleDrawer.DrawBoard(currentBoard);
                                    }
                                }
                            }
                        }
                        else
                        {
                            Board currentBoard = m_Game.GenerateAndGetComputerMove();
                            Screen.Clear();
                            boardConsoleDrawer.DrawBoard(currentBoard);
                        }

                        if (!m_shouldExitFromGame)
                        {
                            Console.WriteLine("These are the 2 chosen cells.{0}Press Enter to continue.{0}", Environment.NewLine);
                            Console.ReadLine();

                            m_Game.DoNextTurn();
                        }
                    }

                    if (m_Game.IsGameEnded)
                    {
                        Console.WriteLine("The winner is {0}!{1}", m_Game.Winner.Name, Environment.NewLine);
                        Console.WriteLine("Score:{0}", Environment.NewLine);
                        Console.WriteLine("{0}: {1} points.{2}", m_Game.FirstPlayerWithScore.Player.Name, m_Game.FirstPlayerWithScore.Score, Environment.NewLine);
                        Console.WriteLine("{0}: {1} points.{2}", m_Game.SecondPlayerWithScore.Player.Name, m_Game.SecondPlayerWithScore.Score, Environment.NewLine);
                        
                        m_shouldExitFromGame = !doesUserWantAnotherRound();
                    }
                }
            }

            Console.WriteLine();
            Console.WriteLine("Thank you for playing!{0}", Environment.NewLine);
            Console.WriteLine("Press any key to continue . . .");
            Console.ReadLine();
        }

        private bool doesUserWantAnotherRound()
        {
            bool retVal = false;

            Console.WriteLine("Would you like to play another round?{0}Type 1 (Yes) or 2 (No).{0}", Environment.NewLine);
            string inputString = Console.ReadLine();

            while (!inputString.Equals("1") && !inputString.Equals("2") && !shouldExit(inputString))
            {
                Console.WriteLine("You typed a wrong input.{0}", Environment.NewLine);
                Console.WriteLine("Would you like to play another round?{0}Type 1 (Yes) or 2 (No).{0}", Environment.NewLine);
                inputString = Console.ReadLine();
            }

            retVal = inputString.Equals("1");
            this.m_shouldExitFromGame = shouldExit(inputString);

            return retVal;
        }

        private Cell getCellFromUser(string i_MessegeToUser)
        {
            Cell retVal = new Cell(0, 'Z');
            string inputString;

            Console.WriteLine(i_MessegeToUser);
            inputString = Console.ReadLine();

            while (inputString != null && !shouldExit(inputString) && retVal.Row == 0 && retVal.Column == 'Z')
            {
                if (inputString.Length == 2 && char.IsDigit(inputString, 0) && char.IsLetter(inputString, 1))
                {
                    int rowNumber = int.Parse(inputString[0].ToString());
                    char columnLetter = inputString[1];

                    if (rowNumber < 1 ||
                        rowNumber > m_Game.PlayingBoard.NumberOfRows ||
                        columnLetter < 'A' ||
                        columnLetter > m_Game.PlayingBoard.GetLastColumnLetter())
                    {
                        Console.WriteLine("The cell you typed does not exist. Please type the 1st cell again.{0}", Environment.NewLine);
                        inputString = Console.ReadLine();
                    }
                    else
                    {
                        if (m_Game.PlayingBoard[rowNumber, columnLetter] != ' ')
                        {
                            Console.WriteLine("The cell you typed is already open. Please type the 1st cell again.{0}", Environment.NewLine);
                            inputString = Console.ReadLine();
                        }
                        else
                        {
                            // The player typed everything correctly.
                            // We can return the cell.
                            retVal = new Cell(rowNumber, columnLetter);
                        }
                    }
                }
                else
                {
                    Console.WriteLine("Your input is not in the correct format. Please type the 1st cell again.{0}", Environment.NewLine);
                    inputString = Console.ReadLine();
                }
            }

            if (inputString != null && shouldExit(inputString))
            {
                m_shouldExitFromGame = true;
            }

            return retVal;
        }

        private Game initGame()
        {
            Game retVal = null;

            Ex02.ConsoleUtils.Screen.Clear();
            Console.WriteLine("Please type the name of the first player.");
            string firstPlayerName = Console.ReadLine();
            m_shouldExitFromGame = shouldExit(firstPlayerName);
            string secondPlayerName = string.Empty;

            if (!m_shouldExitFromGame)
            {
                Console.WriteLine(
                    "Do you want to play against another human player (option 1) or against the computer (option 2)?{0}Plesae type 1 or 2.",
                    Environment.NewLine);
                string playVsPlayerOrComputerInput = Console.ReadLine();
                m_shouldExitFromGame = shouldExit(playVsPlayerOrComputerInput);

                while (playVsPlayerOrComputerInput != null &&
                    !playVsPlayerOrComputerInput.Equals("1") &&
                    !playVsPlayerOrComputerInput.Equals("2") &&
                    !m_shouldExitFromGame)
                {
                    Console.WriteLine("Plesae type only 1 or 2.");
                    playVsPlayerOrComputerInput = Console.ReadLine();
                    m_shouldExitFromGame = shouldExit(playVsPlayerOrComputerInput);
                }

                if (!m_shouldExitFromGame)
                {
                    if (playVsPlayerOrComputerInput.Equals("1"))
                    {
                        Console.WriteLine("Please type the name of the second player.");
                        secondPlayerName = Console.ReadLine();
                        m_shouldExitFromGame = shouldExit(secondPlayerName);
                        if (!m_shouldExitFromGame)
                        {
                            retVal = new Game(firstPlayerName, secondPlayerName);
                        }
                    }
                    else
                    {
                        retVal = new Game(firstPlayerName);
                    }
                }
            }

            return retVal;
        }

        private void initRound()
        {
            Console.WriteLine("You will be asked now to type the height and the width of the game board.{0}The minimal size is 4X4 and the maximal size if 6X6.{0}Also, the total number of cells should be even.", Environment.NewLine);
            Console.WriteLine("Please type the height of the board.");
            string boardHeightInput = Console.ReadLine();
            m_shouldExitFromGame = shouldExit(boardHeightInput);

            if (!m_shouldExitFromGame)
            {
                int boardHeight;
                bool parsingResult = Int32.TryParse(boardHeightInput, out boardHeight);
                while (!m_shouldExitFromGame && (!parsingResult || boardHeight < 4 || boardHeight > 6))
                {
                    Console.WriteLine("Please type the height of the board again.");
                    boardHeightInput = Console.ReadLine();
                    m_shouldExitFromGame = shouldExit(boardHeightInput);
                    parsingResult = Int32.TryParse(boardHeightInput, out boardHeight);
                }

                if (!m_shouldExitFromGame)
                {
                    Console.WriteLine("Please type the width of the board.");
                    string boardWidthInput = Console.ReadLine();
                    m_shouldExitFromGame = shouldExit(boardWidthInput);
                    if (!m_shouldExitFromGame)
                    {
                        int boardWidth;
                        parsingResult = Int32.TryParse(boardWidthInput, out boardWidth);
                        while (!m_shouldExitFromGame && (!parsingResult || boardWidth < 4 || boardWidth > 6 || (boardHeight * boardWidth) % 2 != 0))
                        {
                            Console.WriteLine("Please type the width of the board again.");
                            boardWidthInput = Console.ReadLine();
                            m_shouldExitFromGame = shouldExit(boardWidthInput);
                            parsingResult = Int32.TryParse(boardWidthInput, out boardWidth);
                        }

                        this.m_Game.InitRound(boardHeight, boardWidth);
                    }
                }
            }
        }

        private bool shouldExit(string i_UserInput)
        {
            const bool v_ShouldExit = true;
            bool retVal = !v_ShouldExit;

            if (i_UserInput != null && i_UserInput.ToUpperInvariant().Equals("Q"))
            {
                retVal = v_ShouldExit;
            }

            return retVal;
        }
    }
}
